﻿#region Copyright (c) 2000-2008 Developer Express Inc.
/*
{*******************************************************************}
{                                                                   }
{       Developer Express .NET Component Library                    }
{       AgDataGrid                                 }
{                                                                   }
{       Copyright (c) 2000-2008 Developer Express Inc.              }
{       ALL RIGHTS RESERVED                                         }
{                                                                   }
{   The entire contents of this file is protected by U.S. and       }
{   International Copyright Laws. Unauthorized reproduction,        }
{   reverse-engineering, and distribution of all or any portion of  }
{   the code contained in this file is strictly prohibited and may  }
{   result in severe civil and criminal penalties and will be       }
{   prosecuted to the maximum extent possible under the law.        }
{                                                                   }
{   RESTRICTIONS                                                    }
{                                                                   }
{   THIS SOURCE CODE AND ALL RESULTING INTERMEDIATE FILES           }
{   ARE CONFIDENTIAL AND PROPRIETARY TRADE                          }
{   SECRETS OF DEVELOPER EXPRESS INC. THE REGISTERED DEVELOPER IS   }
{   LICENSED TO DISTRIBUTE THE PRODUCT AND ALL ACCOMPANYING .NET    }
{   CONTROLS AS PART OF AN EXECUTABLE PROGRAM ONLY.                 }
{                                                                   }
{   THE SOURCE CODE CONTAINED WITHIN THIS FILE AND ALL RELATED      }
{   FILES OR ANY PORTION OF ITS CONTENTS SHALL AT NO TIME BE        }
{   COPIED, TRANSFERRED, SOLD, DISTRIBUTED, OR OTHERWISE MADE       }
{   AVAILABLE TO OTHER INDIVIDUALS WITHOUT EXPRESS WRITTEN CONSENT  }
{   AND PERMISSION FROM DEVELOPER EXPRESS INC.                      }
{                                                                   }
{   CONSULT THE END USER LICENSE AGREEMENT FOR INFORMATION ON       }
{   ADDITIONAL RESTRICTIONS.                                        }
{                                                                   }
{*******************************************************************}
*/
#endregion Copyright (c) 2000-2008 Developer Express Inc.

using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Diagnostics;
using System.Globalization;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Controls.Primitives;
using System.Windows.Data;
using System.Windows.Input;
using System.Windows.Threading;
using System.Windows.Media;
using System.Threading;
using System.ComponentModel;
using System.Collections;
using DevExpress.AgMenu.Utils;
using DevExpress.AgMenu.Internal;
namespace DevExpress.AgMenu {
	public enum AgMenuScrollButtonClickMode {
		Click, Hover
	}
	public class AgMenuSubMenuStyleSelector {
		public virtual Style SelectStyle(AgPopupMenu subMenu) { return null; }
	}
	public enum AgMenuCheckAreaDisplayMode {
		ReplaceIcon, AlwaysShowCheckArea, ShowCheckAreaIfChecked
	}
	public delegate void AgMenuItemEventHandler(object sender, AgMenuEventEventArgs e);
	public class AgMenuEventEventArgs : EventArgs {
		public AgMenuItemBase Item { get; private set; }
		public AgMenuEventEventArgs(AgMenuItemBase item) {
			Item = item;
		}
	}
	public delegate void AgMenuPopupEventHandler(object sender, AgMenuPopupEventArgs e);
	public class AgMenuPopupEventArgs : EventArgs {
		public AgMenuItemBase PopupOwnerItem { get; private set; }
		public AgMenuPopupEventArgs(AgMenuItemBase popupOwnerItem) {
			PopupOwnerItem = popupOwnerItem;
		}
	}
	public delegate void AgMenuBeforePopupEventHandler(object sender, AgMenuBeforePopupEventArgs e);
	public class AgMenuBeforePopupEventArgs : AgMenuPopupEventArgs {
		public bool Cancel { get; set; }
		public AgMenuBeforePopupEventArgs(AgMenuItemBase popupOwnerItem)
			: base(popupOwnerItem) {
			Cancel = false;
		}
	}
	public delegate void AgMenuPopupAnimateEventHandler(object sender, AgMenuPopupAnimateEventArgs e);
	public class AgMenuPopupAnimateEventArgs : AgMenuPopupEventArgs {
		public bool IsShowing { get; private set; }
		public bool Handled { get; set; }
		public AgMenuPopupAnimateEventArgs(AgMenuItemBase popupOwnerItem, bool isShowing)
			: base(popupOwnerItem) {
			IsShowing = isShowing;
			Handled = true;
		}
	}
	public class AgMenuTemplateListItem {
		public string Key { get; set; }
		public ControlTemplate Template { get; set; }
	}
	public class AgMenuTemplateList : List<AgMenuTemplateListItem> { }
	public abstract class AgMenuBase : ItemsControl, IAgMenuCheckingControllerClient, IAgMenuPanelOwner {
		class DisplayMemberValueConverter : IValueConverter {
			public object Convert(object value, Type targetType, object parameter, CultureInfo culture) {
				return (value == null) ? "" : value.ToString();
			}
			public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture) {
				throw new NotImplementedException();
			}
		}
		public static readonly DependencyProperty AllowSelectItemsProperty = DependencyProperty.Register("AllowSelectItems", typeof(bool), typeof(AgMenuBase),
			new PropertyMetadata(delegate(DependencyObject d, DependencyPropertyChangedEventArgs e) {
			((AgMenuBase)d).AllowSelectItemsChanged();
		}));
		public static readonly DependencyProperty ItemContainerTemplatesProperty = DependencyProperty.Register("ItemContainerTemplates", typeof(AgMenuTemplateList), typeof(AgMenuBase),
			new PropertyMetadata(delegate(DependencyObject d, DependencyPropertyChangedEventArgs e) {
			((AgMenuBase)d).ItemContainerTemplatesChanged();
		}));
		public static readonly DependencyProperty SelectedItemProperty = DependencyProperty.Register("SelectedItem", typeof(AgMenuItemBase), typeof(AgMenuBase),
			new PropertyMetadata(delegate(DependencyObject d, DependencyPropertyChangedEventArgs e) {
			((AgMenuBase)d).SelectedItemChanged((AgMenuItemBase)e.OldValue);
		}));
		public static readonly DependencyProperty SubMenuStyleProperty = DependencyProperty.Register("SubMenuStyle", typeof(Style), typeof(AgMenuBase),
			new PropertyMetadata(delegate(DependencyObject d, DependencyPropertyChangedEventArgs e) {
			((AgMenuBase)d).SubMenuStyleChanged((Style)e.OldValue);
		}));
		public static readonly DependencyProperty SubMenuStyleSelectorProperty = DependencyProperty.Register("SubMenuStyleSelector", typeof(AgMenuSubMenuStyleSelector),
			typeof(AgMenuBase), new PropertyMetadata((d, e) => ((AgMenuBase)d).PropertyChangedSubMenuStyleSelector()));
		public static readonly DependencyProperty TemplateKeyProperty = DependencyProperty.RegisterAttached("TemplateKey", typeof(string), typeof(AgMenuBase), null);
		#region Fields
		bool hasCheckedItems;
		IAgMenuPanel itemsHost;
		UIElement itemsPresenterContainer;
		AgPopupAnimationType popupAnimationType;
		#endregion
		#region Consts
		public const uint DefaultPopupDelay = 200;
		const string ElementEmptyAreaName = "ElementEmptyArea";
		const string ElementItemsPresenterContainerName = "ItemsPresenterContainer";
		#endregion
		#region Properties
		public bool AllowSelectItems {
			get { return (bool)GetValue(AllowSelectItemsProperty); }
			set { SetValue(AllowSelectItemsProperty, value); }
		}
		public virtual bool IsPopupMenu { get { return false; } }
		public bool IsRootMenu { get { return ParentMenu == null; } }
		public AgMenuTemplateList ItemContainerTemplates {
			get { return (AgMenuTemplateList)GetValue(ItemContainerTemplatesProperty); }
			set { SetValue(ItemContainerTemplatesProperty, value); }
		}
		public virtual AgMenuBase ParentMenu { get { return null; } }
		public AgPopupAnimationType PopupAnimationType {
			get { return (IsRootMenu) ? popupAnimationType : RootMenu.PopupAnimationType; }
			set {
				if(IsRootMenu)
					popupAnimationType = value;
			}
		}
		public AgMenuBase RootMenu {
			get {
				AgMenuBase menu = this;
				while(menu.ParentMenu != null)
					menu = menu.ParentMenu;
				return menu;
			}
		}
		public AgMenuItemBase SelectedItem {
			get { return (AgMenuItemBase)GetValue(SelectedItemProperty); }
			set { SetValue(SelectedItemProperty, value); }
		}
		public Style SubMenuStyle {
			get { return (Style)GetValue(SubMenuStyleProperty); }
			set { SetValue(SubMenuStyleProperty, value); }
		}
		public AgMenuSubMenuStyleSelector SubMenuStyleSelector {
			get { return (AgMenuSubMenuStyleSelector)GetValue(SubMenuStyleSelectorProperty); }
			set { SetValue(SubMenuStyleSelectorProperty, value); }
		}
		protected internal bool HasCheckedItems { get { return hasCheckedItems; } }
		protected IAgMenuPanel ItemsHost {
			get { return itemsHost; }
			set {
				if(value == itemsHost) return;
				itemsHost = value;
				ItemsHostChanged();
			}
		}
		#endregion
		#region Events
		public event AgMenuBeforePopupEventHandler BeforePopup;
		public event AgMenuItemEventHandler ItemChecked;
		public event AgMenuItemEventHandler ItemClick;
		public event AgMenuItemEventHandler ItemUnchecked;
		public event AgMenuPopupAnimateEventHandler PopupAnimate;
		public event AgMenuPopupEventHandler PopupClosed;
		public event AgMenuPopupEventHandler PopupOpened;
		#endregion
		#region Methods
		public AgMenuBase() {
			IsTabStop = true;
			checkingController = CreateCheckingController();
			PopupAnimationType = AgPopupAnimationType.None;
			ScrollButtonClickMode = AgMenuScrollButtonClickMode.Hover;
			KeyDown += OnKeyDown;
			Loaded += OnLoaded;
			LostFocus += OnLostFocus;
			MouseEnter += OnMouseEnter;
			MouseLeave += OnMouseLeave;
			MouseLeftButtonDown += OnMouseLeftButtonDown;
			MouseMove += OnMouseMove;
		}
		public override void OnApplyTemplate() {
			base.OnApplyTemplate();
			itemsPresenterContainer = GetTemplateChild(ElementItemsPresenterContainerName) as UIElement;
		}
		public virtual void CloseAllSubMenus() {
			if(!IsRootMenu)
				ParentMenu.CloseAllSubMenus();
			else {
				CloseSubMenus();
				AutoOpenSubMenusMode = false;
			}
		}
		public void CloseSubMenus() {
			for(int i = 0; i < Items.Count; i++)
				this[i].IsDroppedDown = false;
		}
		public static string GetTemplateKey(ControlTemplate template) {
			return (string)template.GetValue(TemplateKeyProperty);
		}
		public static void SetTemplateKey(ControlTemplate template, string value) {
			template.SetValue(TemplateKeyProperty, value);
		}
		internal bool DoItemBeforePopup(AgMenuItemBase item) {
			return RaiseBeforePopup(item);
		}
		internal void DoItemChecked(AgMenuItemBase item) {
			RaiseItemChecked(item);
		}
		internal void DoItemClick(AgMenuItemBase item) {
			RaiseItemClick(item);
		}
		internal void DoItemSubMenuClosed(AgMenuItemBase item) {
			RaisePopupClosed(item);
		}
		internal void DoItemSubMenuOpened(AgMenuItemBase item) {
			RaisePopupOpened(item);
		}
		internal void DoItemUnchecked(AgMenuItemBase item) {
			RaiseItemUnchecked(item);
		}
		protected override Size ArrangeOverride(Size finalSize) {
			Size result = base.ArrangeOverride(finalSize);
			UpdateIconAreaProperties();
			return result;
		}
		protected internal virtual void ItemIsCheckedChanged(AgMenuItem item) {
			if(item.IsChecked) {
				int itemIndex = -1;
				foreach(object tempItem in Items)
					if(tempItem is AgMenuItem) {
						itemIndex++;
						if(tempItem == item) break;
					}
				Debug.Assert(itemIndex >= 0);
				RaiseInterfacedItemChecked(itemIndex);
			}
			UpdateHasCheckedItems();
		}
		protected internal static void CheckItemState(AgMenuItemBase item, AgMenuItemState oldState) {
			if(item.State != oldState)
				item.Menu.ItemStateChanged(item);
		}
		protected internal virtual void ItemStateChanged(AgMenuItemBase item) {
			item.StateChanged();
		}
		protected internal virtual void UpdateItemTemplate(AgMenuItemBase item) {
			ControlTemplate itemContainerTemplate = GetItemContainerTemplate(item);
			if(itemContainerTemplate != null && itemContainerTemplate != item.Template) {
				if(item.Template != null)
					ItemPrepareForTemplateChanging(item);
				item.Template = itemContainerTemplate;
			}
		}
		protected virtual void AllowSelectItemsChanged() { }
		protected override void ClearContainerForItemOverride(DependencyObject element, object item) {
			base.ClearContainerForItemOverride(element, item);
			if(item != element)
				((AgMenuItemBase)element).Header = null;
			CloseUpController.CheckItemBeforeDeletion((AgMenuItemBase)element);
			SetMenuItemMenu((AgMenuItemBase)element, null);
		}
		protected virtual List<string> GenerateItemTemplateKeys(string baseName, Orientation orientation,
				AgMenuItemPosition itemPosition, AgMenuItemViewStyle itemViewStyle) {
			List<string> result = new List<string>();
			for(int i1 = 0; i1 < 2; i1++) {
				string key1 = baseName;
				for(int i2 = 0; i2 < 2; i2++) {
					string key2 = key1;
					if(i2 == 0)
						key2 += ';' + orientation.ToString();
					for(int i3 = 0; i3 < 2; i3++) {
						string key3 = key2;
						if(i3 == 0)
							key3 += ';' + itemPosition.ToString();
						for(int i4 = 0; i4 < 2; i4++) {
							if(i4 == 0)
								result.Add(key3 + ';' + itemViewStyle.ToString());
							else
								result.Add(key3);
						}
					}
				}
			}
			return result;
		}
		protected override DependencyObject GetContainerForItemOverride() {
			return new AgMenuItem();
		}
		protected override bool IsItemItsOwnContainerOverride(object item) {
			return item is AgMenuItemBase;
		}
		protected virtual void ItemContainerTemplatesChanged() { }
		protected void ItemPrepareForTemplateChanging(AgMenuItemBase item) {
			item.PrepareForTemplateChanging();
		}
		protected virtual void ItemsHostChanged() {
			UpdateHasCheckedItems();
			UpdateIconAreaProperties();
		}
		protected static void MenuItemAssignTemplate(AgMenuItemBase item, DataTemplate template) {
			item.AssignTemplate(template);
		}
		protected override void PrepareContainerForItemOverride(DependencyObject element, object item) {
			base.PrepareContainerForItemOverride(element, item);
			AgMenuItemBase menuItem = (AgMenuItemBase)element;
			bool assignHeader = true;
			if(menuItem != item) {
				if(ItemTemplate != null) {
					MenuItemAssignTemplate(menuItem, ItemTemplate);
					menuItem.DataContext = item;
				}
				if(menuItem.HeaderTemplate == null) {
					if(!string.IsNullOrEmpty(DisplayMemberPath)) {
						Binding binding = new Binding(DisplayMemberPath) { Converter = new DisplayMemberValueConverter() };
						menuItem.SetBinding(AgMenuItemBase.HeaderProperty, binding);
						assignHeader = false;
					}
				}
				if(assignHeader)
					menuItem.Header = item;
			}
			AgMenuBase.SetMenuItemItem(menuItem, item);
			AgMenuBase.SetMenuItemMenu(menuItem, this);
			UpdateItemTemplate(menuItem);
		}
		protected virtual void PropertyChangedSubMenuStyleSelector() { }
		protected virtual bool RaiseBeforePopup(AgMenuItemBase popupOwnerItem) {
			if(BeforePopup != null) {
				AgMenuBeforePopupEventArgs e = new AgMenuBeforePopupEventArgs(popupOwnerItem);
				BeforePopup(this, e);
				return !e.Cancel;
			} else
				return true;
		}
		protected virtual void RaiseItemChecked(AgMenuItemBase item) {
			if(ItemChecked != null)
				ItemChecked(this, new AgMenuEventEventArgs(item));
		}
		protected virtual void RaiseItemClick(AgMenuItemBase item) {
			if(ItemClick != null)
				ItemClick(this, new AgMenuEventEventArgs(item));
		}
		protected virtual void RaiseItemUnchecked(AgMenuItemBase item) {
			if(ItemUnchecked != null)
				ItemUnchecked(this, new AgMenuEventEventArgs(item));
		}
		protected virtual bool RaisePopupAnimate(AgMenuItemBase popupOwnerItem, bool isShowing) {
			if(PopupAnimate != null) {
				AgMenuPopupAnimateEventArgs e = new AgMenuPopupAnimateEventArgs(popupOwnerItem, isShowing);
				PopupAnimate(this, e);
				return !e.Handled;
			} else
				return false;
		}
		protected virtual void RaisePopupClosed(AgMenuItemBase popupOwnerItem) {
			if(PopupClosed != null)
				PopupClosed(this, new AgMenuPopupEventArgs(popupOwnerItem));
		}
		protected virtual void RaisePopupOpened(AgMenuItemBase popupOwnerItem) {
			if(PopupOpened != null)
				PopupOpened(this, new AgMenuPopupEventArgs(popupOwnerItem));
		}
		protected virtual void SelectedItemChanged(AgMenuItemBase oldValue) {
			if(oldValue != null)
				CheckItemState(oldValue, (AgMenuItemState)(((int)oldValue.State) + (int)AgMenuItemState.Selected));
			if(SelectedItem != null)
				CheckItemState(SelectedItem, (AgMenuItemState)(((int)SelectedItem.State) - (int)AgMenuItemState.Selected));
		}
		protected static void SetMenuItemItem(AgMenuItemBase item, object value) {
			item.Item = value;
		}
		protected static void SetMenuItemMenu(AgMenuItemBase item, AgMenuBase value) {
			item.Menu = value;
		}
		protected virtual void SubMenuStyleChanged(Style oldValue) {
		}
		internal bool AnimateItemSubMenu(AgMenuItemBase item, bool isShowing) {
			return RaisePopupAnimate(item, isShowing);
		}
		internal ControlTemplate GetItemContainerTemplate(Type itemType, Orientation itemMenuOrientation,
				AgMenuItemPosition itemPosition, AgMenuItemViewStyle itemViewStyle) {
			ControlTemplate result;
			do {
				result = GetItemContainerTemplateCore(itemType.Name, itemMenuOrientation, itemPosition, itemViewStyle);
				if(result == null)
					if(itemType == typeof(AgMenuItemBase))
						break;
					else
						itemType = itemType.BaseType;
			} while(result == null);
			return result;
		}
		ControlTemplate GetItemContainerTemplate(AgMenuItemBase item) {
			return GetItemContainerTemplate(item.GetType(), GetOrientation(), item.Position, item.ViewStyle);
		}
		ControlTemplate GetItemContainerTemplateCore(string itemTypeName, Orientation itemMenuOrientation,
				AgMenuItemPosition itemPosition, AgMenuItemViewStyle itemViewStyle) {
			List<string> keys = GenerateItemTemplateKeys(itemTypeName, itemMenuOrientation, itemPosition, itemViewStyle);
			if(ItemContainerTemplates != null) {
				foreach(string key in keys)
					foreach(AgMenuTemplateListItem templateListItem in ItemContainerTemplates)
						if(templateListItem.Key == key)
							return templateListItem.Template;
			}
			if(!IsRootMenu)
				return ParentMenu.GetItemContainerTemplateCore(itemTypeName, itemMenuOrientation, itemPosition, itemViewStyle);
			return null;
		}
		void UpdateHasCheckedItems() {
			bool oldHasCheckedItems = hasCheckedItems;
			hasCheckedItems = false;
			foreach(object item in Items)
				if(item is AgMenuItem && (item as AgMenuItem).IsChecked) {
					hasCheckedItems = true;
					break;
				}
			if(hasCheckedItems != oldHasCheckedItems)
				UpdateItemsCheckAreaVisibility();
		}
		#endregion
		#region Mouse behavior
		public static AgMenuItemBase HighlightedItem {
			get { return CloseUpController.HighlightedItem; }
			protected set { CloseUpController.SetHighlightedItem(value); }
		}
		public static readonly DependencyProperty ScrollButtonClickModeProperty = DependencyProperty.Register("ScrollButtonClickMode",
			typeof(AgMenuScrollButtonClickMode), typeof(AgMenuBase), null);
		bool autoOpenSubMenusMode;
		bool openSubMenuOnClick;
		TimeSpan popupDelay = TimeSpan.FromMilliseconds(DefaultPopupDelay);
		public bool OpenSubMenuOnClick { get { return openSubMenuOnClick; } set { openSubMenuOnClick = value; } }
		public TimeSpan PopupDelay {
			get { return IsRootMenu ? popupDelay : RootMenu.PopupDelay; }
			set {
				if(IsRootMenu)
					popupDelay = value;
			}
		}
		public AgMenuScrollButtonClickMode ScrollButtonClickMode {
			get { return (AgMenuScrollButtonClickMode)GetValue(ScrollButtonClickModeProperty); }
			set { SetValue(ScrollButtonClickModeProperty, value); }
		}
		protected internal bool AutoOpenSubMenusMode { get { return autoOpenSubMenusMode; } set { autoOpenSubMenusMode = value; } }
		public AgMenuItemBase GetDroppedDownItem() {
			for(int i = 0; i < Items.Count; i++)
				if(this[i].IsDroppedDown)
					return this[i];
			return null;
		}
		protected virtual void OnMouseEnter(object sender, MouseEventArgs e) {
			CloseUpController.MouseSelectedMenu = this;
		}
		protected virtual void OnMouseLeave(object sender, EventArgs e) {
			if(CloseUpController.MouseSelectedMenu == this)
				CloseUpController.MouseSelectedMenu = null;
		}
		protected virtual void OnMouseLeftButtonDown(object sender, MouseEventArgs e) {
			if(!IsPopupMenu && OpenSubMenuOnClick && CloseUpController.HighlightedItem == null)
				CloseAllSubMenus();
		}
		protected virtual void OnMouseMove(object sender, MouseEventArgs e) {
		}
		#endregion
		#region Checking
		AgMenuCheckingController checkingController;
		protected virtual AgMenuCheckingController CreateCheckingController() {
			return new AgMenuCheckingController(this);
		}
		#endregion
		#region Interfaces
		AgMenuCheckingControllerClientItemCheckedEventHandler interfacedItemChecked;
		void RaiseInterfacedItemChecked(int itemIndex) {
			if(interfacedItemChecked != null)
				interfacedItemChecked(this, new AgMenuCheckingControllerClientItemCheckedEventArgs(itemIndex));
		}
		AgMenuItem GetItem(int itemIndex) {
			AgMenuItem result = null;
			foreach(object item in Items)
				if(item is AgMenuItem)
					if(itemIndex == 0) {
						result = (AgMenuItem)item;
						break;
					} else
						itemIndex--;
			if(result == null) throw new Exception("GetItem result is null");
			return result;
		}
		event AgMenuCheckingControllerClientItemCheckedEventHandler IAgMenuCheckingControllerClient.ItemChecked {
			add { interfacedItemChecked += value; }
			remove { interfacedItemChecked -= value; }
		}
		int IAgMenuCheckingControllerClient.GetItemCount() {
			int result = 0;
			foreach(object item in Items)
				if(item is AgMenuItem)
					result++;
			return result;
		}
		object IAgMenuCheckingControllerClient.GetItemGroup(int itemIndex) {
			return GetItem(itemIndex).Group;
		}
		bool IAgMenuCheckingControllerClient.IsItemChecked(int itemIndex) {
			return GetItem(itemIndex).IsChecked;
		}
		bool IAgMenuCheckingControllerClient.IsRadioItem(int itemIndex) {
			return GetItem(itemIndex).IsRadioItem;
		}
		void IAgMenuCheckingControllerClient.UncheckItem(int itemIndex) {
			GetItem(itemIndex).IsChecked = false;
		}
		#endregion
		#region Appearance
		public static readonly DependencyProperty CheckAreaDisplayModeProperty = DependencyProperty.Register("CheckAreaDisplayMode", typeof(AgMenuCheckAreaDisplayMode), typeof(AgMenuBase),
			new PropertyMetadata(delegate(DependencyObject d, DependencyPropertyChangedEventArgs e) {
			((AgMenuBase)d).CheckAreaDisplayModeChanged((AgMenuCheckAreaDisplayMode)e.OldValue);
		}));
		public static readonly DependencyProperty IconAreaLeftProperty = DependencyProperty.Register("IconAreaLeft", typeof(double), typeof(AgMenuBase),
			new PropertyMetadata(delegate(DependencyObject d, DependencyPropertyChangedEventArgs e) {
			((AgMenuBase)d).IconAreaLeftChanged((double)e.OldValue);
		}));
		public static readonly DependencyProperty IconAreaWidthProperty = DependencyProperty.Register("IconAreaWidth", typeof(double), typeof(AgMenuBase),
			new PropertyMetadata(delegate(DependencyObject d, DependencyPropertyChangedEventArgs e) {
			((AgMenuBase)d).IconAreaWidthChanged((double)e.OldValue);
		}));
		public static readonly DependencyProperty TemplateCollectionProperty = DependencyProperty.Register("TemplateCollection", typeof(AgMenuTemplateList), typeof(AgMenuBase),
			new PropertyMetadata(delegate(DependencyObject d, DependencyPropertyChangedEventArgs e) {
			((AgMenuBase)d).TemplateCollectionChanged();
		}));
		public AgMenuCheckAreaDisplayMode CheckAreaDisplayMode {
			get { return (AgMenuCheckAreaDisplayMode)GetValue(CheckAreaDisplayModeProperty); }
			set { SetValue(CheckAreaDisplayModeProperty, value); }
		}
		public double IconAreaLeft {
			get { return (double)GetValue(IconAreaLeftProperty); }
		}
		public double IconAreaWidth {
			get { return (double)GetValue(IconAreaWidthProperty); }
		}
		public AgMenuTemplateList TemplateCollection {
			get { return (AgMenuTemplateList)GetValue(TemplateCollectionProperty); }
			set { SetValue(TemplateCollectionProperty, value); }
		}
		protected internal virtual bool HasEmptyArea() {
			FrameworkElement emptyArea = GetTemplateChild(ElementEmptyAreaName) as FrameworkElement;
			return (emptyArea != null) && ((GetOrientation() == Orientation.Horizontal) ? emptyArea.ActualWidth != 0 : emptyArea.ActualHeight != 0);
		}
		protected virtual void CheckAreaDisplayModeChanged(AgMenuCheckAreaDisplayMode oldValue) {
			UpdateItemsCheckAreaVisibility();
		}
		protected virtual ControlTemplate FindTemplate() {
			if(TemplateCollection == null) return null;
			for(int i = 0; i < 2; i++)
				foreach(AgMenuTemplateListItem templateListItem in TemplateCollection) {
					string key = templateListItem.Key;
					if(i == 0 && key == GetOrientation().ToString() || i == 1 && key == null)
						return templateListItem.Template;
				}
			return null;
		}
		protected virtual void IconAreaLeftChanged(double oldValue) { }
		protected virtual void IconAreaWidthChanged(double oldValue) { }
		protected internal abstract Orientation GetOrientation();
		protected virtual void TemplateCollectionChanged() { UpdateTemplate(); }
		protected void UpdateItemCheckAreaVisibility(AgMenuItem item) {
			item.UpdateCheckAreaVisibility();
		}
		protected virtual void UpdateTemplate() {
			ControlTemplate template = FindTemplate();
			if(template != null && template != Template) {
				IEnumerable prevItemsSource = ItemsSource;
				if(ItemsSource != null)
					ItemsSource = null;
				List<object> prevItems = null;
				if(prevItemsSource == null) {
					prevItems = new List<object>();
					foreach(object item in Items)
						prevItems.Add(item);
					Items.Clear();
				}
				ItemsHost = null;
				try {
					Template = template;
					UpdateLayout();
				} finally {
					ItemsSource = prevItemsSource;
					if(ItemsSource == null)
						foreach(object item in prevItems)
							Items.Add(item);
				}
			}
		}
		void UpdateIconAreaProperties() {
			if(this.GetParent() != null && ItemsHost != null) {
				SetValue(IconAreaLeftProperty, ((FrameworkElement)ItemsHost).GetPositionNew(this).X + ItemsHost.IconAreaLeft);
				SetValue(IconAreaWidthProperty, (ItemsHost as IAgMenuPanel).IconAreaWidth);
			}
		}
		void UpdateItemsCheckAreaVisibility() {
			foreach(object item in Items)
				if(item is AgMenuItem)
					UpdateItemCheckAreaVisibility(item as AgMenuItem);
		}
		#endregion
		#region IAgMenuPanelOwner members
		EventHandler orientationChanged;
		IAgMenuPanel IAgMenuPanelOwner.ItemsHost { get { return ItemsHost; } set { ItemsHost = value; } }
		Orientation IAgMenuPanelOwner.Orientation { get { return GetOrientation(); } }
		event EventHandler IAgMenuPanelOwner.OrientationChanged {
			add { orientationChanged += value; }
			remove { orientationChanged -= value; }
		}
		protected virtual void RaiseOrientationChanged() {
			if(orientationChanged != null)
				orientationChanged(this, new EventArgs());
		}
		#endregion
		#region Keyboard
		protected virtual void OnKeyDown(object sender, KeyEventArgs e) {
			if(!e.Handled)
				e.Handled = ProcessKeyDown(e.Key);
		}
		protected virtual void OnLoaded(object sender, RoutedEventArgs e) {
		}
		protected internal virtual void OnLostFocus(object sender, RoutedEventArgs e) {
			if(HighlightedItem != null && HighlightedItem.Menu.RootMenu == this)
				CloseUpController.SetHighlightedItem(null);
		}
		protected internal bool ProcessKeyDown(Key key) {
			if(IsHorizontal && (key == Key.Left || key == Key.Right) ||
					!IsHorizontal && (key == Key.Up || key == Key.Down))
				if(CheckSelectedItem(key == Key.Right || key == Key.Down)) return true;
			bool result = (HighlightedItem != null) && HighlightedItem.HandleKeyDown(key);
			if(result) return result;
			switch(key) {
				case Key.Down:
					result = PressedDownKey();
					break;
				case Key.Right:
					result = PressedRightKey();
					break;
				case Key.Left:
					result = PressedLeftKey();
					break;
				case Key.Up:
					result = PressedUpKey();
					break;
				case Key.Escape:
					result = PressedEscapeKey();
					break;
			}
			if(result && HighlightedItem != null)
				HighlightedItem.Menu.MakeItemVisible(HighlightedItem);
			return result;
		}
		void MakeItemVisible(AgMenuItemBase item) {
			if(itemsPresenterContainer is IAgMenuScrollViewer) {
				(itemsPresenterContainer as IAgMenuScrollViewer).MakeItemVisible(Items.IndexOf(item.Item));
			}
		}
		AgMenuItemBase GetNextItem(AgMenuItemBase item, bool isNext) {
			AgMenuBase menu = item.Menu;
			if(menu == null) return item;
			int index = menu.Items.IndexOf(item.Item);
			return menu.GetNextItem(index, isNext);
		}
		AgMenuItemBase GetNextItem(AgMenuItemBase item) {
			return GetNextItem(item, true);
		}
		AgMenuItemBase GetPrevItem(AgMenuItemBase item) {
			return GetNextItem(item, false);
		}
		internal AgMenuItemBase GetNextItem(int itemIndex) {
			return GetNextItem(itemIndex, true);
		}
		AgMenuItemBase GetPrevItem(int itemIndex) {
			return GetNextItem(itemIndex, false);
		}
		AgMenuItemBase GetNextItem(int currentIndex, bool isNext) {
			if(currentIndex != -1 && (currentIndex < 0 || currentIndex >= Items.Count))
				throw new Exception();
			if(Items.Count == 0) return null;
			int index = currentIndex;
			int startIndex = -1;
			do {
				index += isNext ? 1 : -1;
				if(index < 0)
					index = Items.Count - 1;
				else
					if(index == Items.Count)
						index = 0;
				if(startIndex == -1)
					startIndex = index;
				else
					if(index == startIndex)
						break;
			} while(!this[index].CanFocus());
			return this[index].CanFocus() ? this[index] : null;
		}
		void MoveNextItem() {
			HighlightedItem = GetNextItem(HighlightedItem);
		}
		void MovePrevItem() {
			HighlightedItem = GetPrevItem(HighlightedItem);
		}
		void DropItem() {
			HighlightedItem.IsDroppedDown = true;
			if(HighlightedItem.IsDroppedDown) {
				HighlightedItem.SubMenu.UpdateLayout();
				HighlightedItem = HighlightedItem.SubMenu.GetNextItem(-1);
			} else {
				if(!HighlightedItem.Menu.IsRootMenu && RootMenu.IsHorizontal) {
					HighlightedItem = RootMenu.GetNextItem(RootMenu.GetDroppedDownItem());
					DropItem();
				}
			}
		}
		void UnDropItem() {
			AgMenuItemBase parent = HighlightedItem.ParentItem;
			if(parent != null) {
				parent.IsDroppedDown = false;
				if(!parent.Menu.IsRootMenu)
					HighlightedItem = parent;
				else {
					if(parent.Menu.IsHorizontal) {
						HighlightedItem = parent.Menu.GetPrevItem(parent);
						DropItem();
					} else {
						HighlightedItem = parent;
						HighlightedItem.IsDroppedDown = false;
					}
				}
			}
		}
		protected internal virtual bool PressedDownKey() {
			if(HighlightedItem != null) {
				if(HighlightedItem.Menu.IsHorizontal)
					DropItem();
				else {
					MoveNextItem();
				}
				return true;
			} else
				return false;
		}
		private bool PressedUpKey() {
			if(HighlightedItem != null) {
				if(HighlightedItem.Menu.IsHorizontal)
					DropItem();
				else {
					MovePrevItem();
				}
				return true;
			} else
				return false;
		}
		protected bool IsHorizontal { get { return GetOrientation() == Orientation.Horizontal; } }
		protected internal virtual bool PressedRightKey() {
			if(HighlightedItem != null) {
				if(HighlightedItem.Menu.IsHorizontal)
					MoveNextItem();
				else
					DropItem();
				return true;
			} else
				return false;
		}
		protected internal virtual bool PressedLeftKey() {
			if(HighlightedItem != null) {
				if(HighlightedItem.Menu.IsHorizontal)
					MovePrevItem();
				else
					UnDropItem();
				return true;
			} else
				return false;
		}
		protected internal bool PressedEscapeKey() {
			if(HighlightedItem == null) return false;
			if(HighlightedItem.ParentItem != null) {
				HighlightedItem = HighlightedItem.ParentItem;
				HighlightedItem.IsDroppedDown = false;
			} else {
				HighlightedItem = null;
			}
			return true;
		}
		bool CheckSelectedItem(bool isNext) {
			if(HighlightedItem == null) {
				HighlightedItem = GetNextItem(-1, isNext);
				return HighlightedItem != null;
			}
			return false;
		}
		#endregion
		public AgMenuItemBase this[int i] {
			get {
				if(Items[i] is AgMenuItemBase) return Items[i] as AgMenuItemBase;
				if(ItemsHost != null)
					return ItemsHost.GetItemByIndex(i) as AgMenuItemBase;
				else
					return null;
			}
		}
	}
	public class AgMenu : AgMenuBase {
		public static readonly DependencyProperty OrientationProperty = DependencyProperty.Register("Orientation", typeof(Orientation), typeof(AgMenu),
			new PropertyMetadata((d, e) => ((AgMenu)d).PropertyChangedOrientation((Orientation)e.OldValue)));
		public Orientation Orientation {
			get { return (Orientation)GetValue(OrientationProperty); }
			set { SetValue(OrientationProperty, value); }
		}
		public AgMenu() {
			DefaultStyleKey = typeof(AgMenu);
			Orientation = Orientation.Horizontal;
		}
		protected internal override Orientation GetOrientation() {
			return Orientation;
		}
		protected virtual void PropertyChangedOrientation(Orientation oldValue) {
			UpdateTemplate();
			RaiseOrientationChanged();
		}
	}
	public class AgPopupMenu : AgMenuBase {
		public static readonly DependencyProperty PopupOffsetProperty = DependencyProperty.Register("PopupOffset", typeof(Thickness), typeof(AgPopupMenu), null);
		#region Fields
		UIElement popupElement;
		Rect popupElementRect;
		Orientation popupAlign;
		AgAnimatedPopup popup;
		static List<AgPopupMenu> visiblePopupMenus = new List<AgPopupMenu>();
		#endregion
		#region Properties
		public Popup Container { get; set; }
		public override bool IsPopupMenu { get { return true; } }
		public AgAnimatedPopup MenuPopup { get { return popup; } }
		public UIElement PopupElement {
			get { return popupElement; }
			set {
				popupElement = value;
				UpdateScrollButtonClickModeFromParentMenu();
			}
		}
		public Rect PopupElementRect { get { return popupElementRect; } set { popupElementRect = value; } }
		public Thickness PopupOffset {
			get { return (Thickness)GetValue(PopupOffsetProperty); }
			set { SetValue(PopupOffsetProperty, value); }
		}
		public Orientation PopupAlign { get { return popupAlign; } set { popupAlign = value; } }
		public override AgMenuBase ParentMenu { get { return IsItemSubMenu ? (PopupElement as AgMenuItemBase).Menu : null; } }
		public static int VisiblePopupMenuCount { get { return visiblePopupMenus.Count; } }
		protected bool IsItemSubMenu { get { return PopupElement is AgMenuItemBase; } }
		protected Rect RealOwnerBounds { get; set; }
		#endregion
		#region Methods
		public AgPopupMenu() {
			DefaultStyleKey = typeof(AgPopupMenu);
			this.SetVisible(false);
		}
		public override void CloseAllSubMenus() {
			bool isRootMenu = IsRootMenu;
			base.CloseAllSubMenus();
			if(isRootMenu) {
				CloseUp();
			}
		}
		public virtual void CloseUp() {
			if(popup == null || !popup.IsOpen) return;
			CloseSubMenus();
			CloseUpController.CloseUp(this);
			popup.Closed += OnPopupClosed;
			if(!DoAnimation(false))
				popup.IsOpen = false;
		}
		public static AgPopupMenu GetVisiblePopupMenu(int index) { return visiblePopupMenus[index]; }
		System.Windows.Controls.Panel ParentPanel { get { return this.GetParent() as System.Windows.Controls.Panel; } }
		public virtual void Popup() {
			if(PopupElement == null) throw new Exception("PopupElement is null in popup");
			if(IsRootMenu && !RaiseBeforePopup(null)) return;
			if(ParentPanel != null)
				ParentPanel.Children.Remove(this); 
			if(popup != null)
				ForcedCloseUp();
			popup = new AgAnimatedPopup(IsItemSubMenu ? PopupElement as AgMenuItemBase : null, Container) { IsOpen = false, SlideOrientation = GetSlideOrientation() };
			this.SetVisible(true);
			popup.Child = this;
			if(ItemsHost != null) {
				SetPopupBounds();
			}
			popup.Opened += OnPopupOpened;
			popup.IsOpen = true;
		}
		public void Popup(UIElement popupElement, Point position) {
			Popup(popupElement, new Rect(position, position));
		}
		public void Popup(UIElement popupElement, Rect popupElementRect) {
			PopupElement = popupElement;
			PopupElementRect = popupElementRect;
			Popup();
		}
		protected internal virtual void ForcedCloseUp() {
			popup.Closed -= OnPopupClosed;
			popup.IsOpen = false;
			OnPopupClosed(popup, null);
		}
		protected void CalcRealOwnerBounds() {
			Rect realOwnerBounds = PopupElementRect;
			if(PopupElementRect.Width != 0 && PopupElementRect.Height != 0) {
				if(-(PopupOffset.Left + PopupOffset.Right) < realOwnerBounds.Width) {
					realOwnerBounds.X -= PopupOffset.Left;
					realOwnerBounds.Width += PopupOffset.Left + PopupOffset.Right;
				}
				if(-(PopupOffset.Top + PopupOffset.Bottom) < realOwnerBounds.Height) {
					realOwnerBounds.Y -= PopupOffset.Top;
					realOwnerBounds.Height += PopupOffset.Top + PopupOffset.Bottom;
				}
			}
			RealOwnerBounds = realOwnerBounds;
		}
		protected override void OnMouseMove(object sender, MouseEventArgs e) {
			base.OnMouseMove(sender, e);
			if(!(RootMenu.IsPopupMenu || RootMenu.OpenSubMenuOnClick)) return;
			AgMenuItemBase droppedDownItem = GetDroppedDownItem();
			CloseUpController.SetCloseUpTimerTarget((droppedDownItem == null || droppedDownItem == CloseUpController.HighlightedItem) ? null : droppedDownItem);
		}
		protected virtual void CheckHeight() {
			if(popup.VerticalOffset < 0) {
				double bottom = popup.VerticalOffset + DesiredSize.Height;
				MaxHeight = bottom;
				InvalidateMeasureWithChildren(this);
				Measure(new Size(Double.PositiveInfinity, Double.PositiveInfinity));
				popup.VerticalOffset = bottom - DesiredSize.Height;
			} else
				if(popup.VerticalOffset + DesiredSize.Height > Application.Current.Host.Content.ActualHeight) {
					MaxHeight = Application.Current.Host.Content.ActualHeight - popup.VerticalOffset;
					InvalidateMeasureWithChildren(this);
					Measure(new Size(Double.PositiveInfinity, Double.PositiveInfinity));
				}
		}
		protected virtual bool DoAnimation(bool isShowing) {
			bool needsAnimation = true;
			if(IsItemSubMenu)
				needsAnimation = !MenuItemDoAnimateSubMenu(PopupElement as AgMenuItemBase, isShowing);
			else
				needsAnimation = !RaisePopupAnimate(null, isShowing);
			if(isShowing && needsAnimation)
				return popup.Animate(GetPopupAnimationType());
			else
				return !needsAnimation;
		}
		protected virtual Point GetPositionForPopup() {
			CalcRealOwnerBounds();
			return new Point(GetXPositionForPopup(), GetYPositionForPopup());
		}
		bool BoundsXTest { get { return RealOwnerBounds.Left + DesiredSize.Width > HostContentWidth; } }
		bool BoundsYTest { get { return RealOwnerBounds.Top + DesiredSize.Height > HostContentHeight; } }
		double HostContentWidth { get { return Application.Current.Host.Content.ActualWidth; } }
		double HostContentHeight { get { return Application.Current.Host.Content.ActualHeight; } }
		protected virtual double GetXPositionForPopup() {
			AgMenuBase parentMenu = ParentMenu;
			double result;
			if(RealOwnerBounds.Width == 0) {
				if(BoundsXTest) {
					result = RealOwnerBounds.Left - DesiredSize.Width;
					if(result < 0)
						result = Math.Max(HostContentWidth - DesiredSize.Width, 0);
				} else
					result = Math.Max(RealOwnerBounds.Left, 0);
			} else {
				if(PopupAlign == Orientation.Vertical) {
					result = RealOwnerBounds.Left;
					if(BoundsXTest)
						result = HostContentWidth - DesiredSize.Width;
					result = Math.Max(result, 0);
				} else {
					result = RealOwnerBounds.Right - 1;
					if(result + DesiredSize.Width > HostContentWidth) {
						result = RealOwnerBounds.Left - DesiredSize.Width + 1;
						popup.IsRightToLeftAnimation = true;
						if(result < 0)
							if(DesiredSize.Width - RealOwnerBounds.Left >= RealOwnerBounds.Right - (HostContentWidth - DesiredSize.Width)) {
								result = Math.Max(HostContentWidth - DesiredSize.Width - 1, 0);
								popup.IsRightToLeftAnimation = false;
							} else
								result = 0;
					}
				}
			}
			return result;
		}
		protected virtual double GetYPositionForPopup() {
			AgMenuBase parentMenu = ParentMenu;
			double result;
			if(RealOwnerBounds.Height == 0) {
				result = RealOwnerBounds.Top;
				if(BoundsYTest)
					if(DesiredSize.Height <= RealOwnerBounds.Top)
						result = RealOwnerBounds.Top - DesiredSize.Height;
					else
						result = Math.Max(HostContentHeight - DesiredSize.Height, 0);
			} else
				if(PopupAlign == Orientation.Vertical) {
					result = RealOwnerBounds.Bottom - 1;
					if(result + DesiredSize.Height > HostContentHeight)
						if(RealOwnerBounds.Top > HostContentHeight - RealOwnerBounds.Bottom) {
							result = RealOwnerBounds.Top - DesiredSize.Height + 1;
							popup.IsBottomToTopAnimation = true;
						}
				} else {
					result = RealOwnerBounds.Top;
					if(BoundsYTest)
						result = HostContentHeight - DesiredSize.Height;
					result = Math.Max(result, 0);
				}
			return result;
		}
		protected override void ItemsHostChanged() {
			base.ItemsHostChanged();
			SetPopupBounds();
		}
		protected bool MenuItemDoAnimateSubMenu(AgMenuItemBase item, bool isShowing) {
			return item.DoAnimateSubMenu(isShowing);
		}
		protected void MenuItemSubMenuClosed() {
			(PopupElement as AgMenuItemBase).OnSubMenuClosed();
		}
		protected void MenuItemSubMenuOpened() {
			(PopupElement as AgMenuItemBase).OnSubMenuOpened();
		}
		protected virtual void OnPopupClosed(object sender, EventArgs e) {
			UnregisterVisiblePopupMenu(this);
			popup = null;
			this.SetVisible(false);
			if(IsItemSubMenu)
				MenuItemSubMenuClosed();
			else
				RaisePopupClosed(null);
		}
		protected virtual void OnPopupOpened(object sender, EventArgs e) {
			if(ItemsHost == null) {
				UpdateLayout();
			}
			RegisterVisiblePopupMenu(this);
			if(IsItemSubMenu)
				MenuItemSubMenuOpened();
			else
				RaisePopupOpened(null);
		}
		protected virtual void RegisterVisiblePopupMenu() {
			if(visiblePopupMenus.Contains(this)) throw new Exception("RegisterVisiblePopupMenu requires not fit");
			visiblePopupMenus.Add(this);
			if(VisiblePopupMenuCount == 1) {
				RootVisualHelper.SubscribeOnClick();
				RootVisualHelper.OnClick += OnRootMouseLeftButtonDown;
			}
		}
		protected static void RegisterVisiblePopupMenu(AgPopupMenu menu) {
			if(menu != null)
				menu.RegisterVisiblePopupMenu();
		}
		protected virtual void SetPopupBounds() {
			InvalidateMeasureWithChildren(this);
			Measure(new Size(Double.PositiveInfinity, Double.PositiveInfinity));
			Point p = GetPositionForPopup();
			popup.HorizontalOffset = p.X;
			popup.VerticalOffset = p.Y;
			CheckHeight();
			DoAnimation(true);
		}
		protected static void UnregisterVisiblePopupMenu(AgPopupMenu menu) {
			if(menu != null)
				menu.UnregisterVisiblePopupMenu();
		}
		protected virtual void UnregisterVisiblePopupMenu() {
			if(!visiblePopupMenus.Contains(this)) throw new Exception("UnregisterVisiblePopupMenu requires not fit");
			visiblePopupMenus.Remove(this);
			if(visiblePopupMenus.Count == 0) {
				RootVisualHelper.UnsubscribeOnClick();
				RootVisualHelper.OnClick -= OnRootMouseLeftButtonDown;
			}
		}
		void InvalidateMeasureWithChildren(UIElement element) {
			element.InvalidateMeasure();
			for(int i = 0; i < VisualTreeHelper.GetChildrenCount(element); i++) {
				InvalidateMeasureWithChildren((UIElement)VisualTreeHelper.GetChild(element, i));
			}
		}
		AgPopupAnimationType GetPopupAnimationType() {
			if(IsRootMenu) {
				return (PopupAnimationType == AgPopupAnimationType.None) ? AgPopupAnimationType.None : AgPopupAnimationType.Fade;
			} else
				return PopupAnimationType;
		}
		Orientation GetSlideOrientation() {
			return (PopupAlign == Orientation.Vertical) ? Orientation.Vertical : Orientation.Horizontal;
		}
		static void OnRootMouseLeftButtonDown(object sender, MouseEventArgs e) {
			RootVisualHelper.UnsubscribeOnClick();
			RootVisualHelper.OnClick -= OnRootMouseLeftButtonDown;
			Point p = e.GetPosition(null);
			foreach(AgPopupMenu menu in visiblePopupMenus)
				if(menu.GetBoundsNew(null).Contains(p) || menu.RootMenu.GetBoundsNew(null).Contains(p)) return;
			AgMenuBase rootMenu = visiblePopupMenus[0].RootMenu;
			if(rootMenu.IsPopupMenu)
				(rootMenu as AgPopupMenu).CloseUp();
			else
				rootMenu.CloseAllSubMenus();
		}
		void UpdateScrollButtonClickModeFromParentMenu() {
			if(!IsRootMenu)
				ScrollButtonClickMode = ParentMenu.ScrollButtonClickMode;
		}
		#endregion
		#region Appearance
		protected internal override Orientation GetOrientation() {
			return Orientation.Vertical;
		}
		#endregion
	}
}
namespace DevExpress.AgMenu.Internal {
	public interface IAgMenuCheckingControllerClient {
		event AgMenuCheckingControllerClientItemCheckedEventHandler ItemChecked;
		int GetItemCount();
		object GetItemGroup(int itemIndex);
		bool IsItemChecked(int itemIndex);
		bool IsRadioItem(int itemIndex);
		void UncheckItem(int itemIndex);
	}
	public interface IAgMenuPanelOwner {
		IAgMenuPanel ItemsHost { get; set; }
		Orientation Orientation { get; }
		event EventHandler OrientationChanged;
	}
	public delegate void AgMenuCheckingControllerClientItemCheckedEventHandler(object sender, AgMenuCheckingControllerClientItemCheckedEventArgs e);
	public class AgMenuCheckingControllerClientItemCheckedEventArgs : EventArgs {
		int itemIndex;
		public int ItemIndex { get { return this.itemIndex; } }
		public AgMenuCheckingControllerClientItemCheckedEventArgs(int itemIndex) { this.itemIndex = itemIndex; }
	}
	public class AgMenuCheckingController {
		IAgMenuCheckingControllerClient client;
		protected IAgMenuCheckingControllerClient Client { get { return client; } }
		public AgMenuCheckingController(IAgMenuCheckingControllerClient client) {
			this.client = client;
			this.client.ItemChecked += ItemChecked;
		}
		protected virtual void DoItemChecked(int itemIndex) {
			if(Client.IsRadioItem(itemIndex))
				for(int i = 0; i < Client.GetItemCount(); i++)
					if(i != itemIndex && Client.IsItemChecked(i) && Client.IsRadioItem(i) && Object.Equals(Client.GetItemGroup(i), Client.GetItemGroup(itemIndex)))
						Client.UncheckItem(i);
		}
		void ItemChecked(object sender, AgMenuCheckingControllerClientItemCheckedEventArgs e) {
			DoItemChecked(e.ItemIndex);
		}
	}
	public static class CloseUpController {
		static DispatcherTimer closeUpTimer;
		static AgMenuItemBase closeUpTimerTarget;
		static AgMenuBase mouseSelectedMenu;
		static AgMenuItemBase highlightedItem;
		internal static AgMenuItemBase HighlightedItem { get { return highlightedItem; } }
		internal static AgMenuBase MouseSelectedMenu {
			get { return mouseSelectedMenu; }
			set {
				if(mouseSelectedMenu == value) return;
				mouseSelectedMenu = value;
				CheckSubMenusToCloseUp();
			}
		}
		internal static void CloseUp(AgPopupMenu menu) {
			CheckHighlightedItemAndMenuBeforeHiding(menu);
			if(menu.PopupElement is AgMenuItemBase && menu.PopupElement == CloseUpTimerTarget)
				SetCloseUpTimerTarget(null);
		}
		internal static bool IsTargetForClosingUp(AgMenuItemBase item) {
			return item == CloseUpTimerTarget;
		}
		internal static void CheckItemBeforeDeletion(AgMenuItemBase item) {
			item.IsDroppedDown = false;
			if(item == HighlightedItem)
				highlightedItem = null;
			if(item == CloseUpTimerTarget) {
				StopCloseUpTimer();
				closeUpTimerTarget = null;
			}
		}
		internal static void CheckSubMenusToCloseUp() {
			if(AgPopupMenu.VisiblePopupMenuCount == 0)
				SetCloseUpTimerTarget(null);
			else {
				AgPopupMenu menu = AgPopupMenu.GetVisiblePopupMenu(0);
				if(!(menu.IsRootMenu || menu.ParentMenu.OpenSubMenuOnClick))
					SetCloseUpTimerTarget(GetNewCloseUpTimerTarget());
			}
		}
		internal static void SetHighlightedItem(AgMenuItemBase value) {
			if(value == highlightedItem) return;
			if(value != null && value.Menu != null && value.Menu.Visibility != Visibility.Visible) return; 
			AgMenuItemState oldHighlightedItemOldState = (highlightedItem != null) ? highlightedItem.State : AgMenuItemState.Normal;
			AgMenuItemState highlightedItemOldState = (value != null) ? value.State : AgMenuItemState.Normal;
			AgMenuItemBase oldHighlightedItem = highlightedItem;
			highlightedItem = value;
			if(oldHighlightedItem != null)
				AgMenuBase.CheckItemState(oldHighlightedItem, oldHighlightedItemOldState);
			if(highlightedItem != null)
				AgMenuBase.CheckItemState(highlightedItem, highlightedItemOldState);
			CloseUpController.CheckSubMenusToCloseUp();
		}
		internal static void SetCloseUpTimerTarget(AgMenuItemBase value) {
			if(CloseUpTimerTarget == value) return;
			AgMenuItemState oldCloseUpTimerTargetOldState = (closeUpTimerTarget != null) ? closeUpTimerTarget.State : AgMenuItemState.Normal;
			AgMenuItemState closeUpTimerTargetOldState = (value != null) ? value.State : AgMenuItemState.Normal;
			AgMenuItemBase oldCloseUpTimerTarget = closeUpTimerTarget;
			closeUpTimerTarget = value;
			if(oldCloseUpTimerTarget != null) {
				StopCloseUpTimer();
				AgMenuBase.CheckItemState(oldCloseUpTimerTarget, oldCloseUpTimerTargetOldState);
			}
			if(closeUpTimerTarget != null) {
				AgMenuBase.CheckItemState(closeUpTimerTarget, closeUpTimerTargetOldState);
				StartCloseUpTimer();
			}
		}
		static AgMenuItemBase CloseUpTimerTarget { get { return closeUpTimerTarget; } }
		static void CheckHighlightedItemAndMenuBeforeHiding(AgMenuBase menu) {
			if(HighlightedItem != null && HighlightedItem.Menu == menu)
				SetHighlightedItem(null);
			if(MouseSelectedMenu == menu)
				MouseSelectedMenu = null;
		}
		static AgMenuItemBase GetNewCloseUpTimerTarget() {
			if(AgPopupMenu.VisiblePopupMenuCount == 0)
				return null;
			AgPopupMenu menu = AgPopupMenu.GetVisiblePopupMenu(0);
			if(menu.IsRootMenu || menu.ParentMenu.OpenSubMenuOnClick)
				return null;
			AgMenuItemBase newCloseUpTimerTarget = null;
			for(int i = AgPopupMenu.VisiblePopupMenuCount - 1; i >= 0; i--) {
				menu = AgPopupMenu.GetVisiblePopupMenu(i);
				if(menu.IsRootMenu || menu == MouseSelectedMenu) break;
				if(menu.PopupElement is AgMenuItemBase && menu.PopupElement != HighlightedItem)
					newCloseUpTimerTarget = (menu.PopupElement as AgMenuItemBase);
			};
			return newCloseUpTimerTarget;
		}
		static bool FindParentMenuForSelectedItem(AgMenuItemBase item, AgMenuBase menu) {
			if(item == null || menu == null) return false;
			if(item.Menu == menu) return true;
			return FindParentMenuForSelectedItem(item.ParentItem, menu);
		}
		static void OnCloseUpTimerTick(object sender, EventArgs e) {
			StopCloseUpTimer();
			if(CloseUpTimerTarget != null && (HighlightedItem == null || !FindParentMenuForSelectedItem(HighlightedItem, CloseUpTimerTarget.SubMenu))) {
				CloseUpTimerTarget.IsDroppedDown = false;
				SetCloseUpTimerTarget(null);
			}
		}
		static void StartCloseUpTimer() {
			if(closeUpTimer != null || AgPopupMenu.VisiblePopupMenuCount == 0)
				throw new Exception("StartCloseUpTimer requires not fit");
			TimeSpan closeUpDelay = AgPopupMenu.GetVisiblePopupMenu(0).PopupDelay;
			if(closeUpDelay == TimeSpan.Zero) {
				OnCloseUpTimerTick(null, null);
				return;
			}
			closeUpTimer = new DispatcherTimer();
			closeUpTimer.Interval = closeUpDelay;
			closeUpTimer.Tick += OnCloseUpTimerTick;
			closeUpTimer.Start();
		}
		static void StopCloseUpTimer() {
			if(closeUpTimer == null) return;
			closeUpTimer.Stop();
			closeUpTimer = null;
		}
	}
}
